home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Graphics⁄Sound / RTrace-1.0-src / macfiles.c < prev    next >
Text File  |  1992-10-25  |  62KB  |  1,654 lines

  1. /*****************************************************************************\
  2. * macfiles.c                                                                  *
  3. *                                                                             *
  4. * This file contains code which is specific to the Macintosh.  It implements  *
  5. * the opening and saving of files for RTrace.                                 *
  6. \*****************************************************************************/
  7.  
  8. #include <string.h>
  9. #include <stdio.h>
  10. #include <Folders.h>
  11. #include <Script.h>
  12. #include "defs.h"
  13. #include "extern.h"
  14. #include "macerrors.h"
  15.  
  16.  
  17. /* types */
  18. typedef
  19. struct
  20.     {
  21.     
  22.     short    prefs_version;
  23.     Rect    options_window_position;
  24.     Rect    image_window_position;
  25.     Rect    log_window_position;
  26.     Rect    status_window_position;
  27.     Rect    animation_window_position;
  28.     Boolean show_image_rendering;
  29.     Boolean allow_background_tasks;
  30.     Boolean keep_image_in_memory;
  31.     Boolean show_status_window_flag;
  32.     Boolean show_about_window_flag;
  33.     Boolean hide_options_window_flag;
  34.     long    time_between_events;
  35.     
  36.     } preferences_struct;
  37.  
  38. #define CURRENT_PREFS_VERSION    2
  39.  
  40.  
  41. /* externals */
  42. extern Boolean        keep_image_in_memory;    /* TRUE if we keep a pixmap in memory */
  43. extern Boolean        show_image_rendering;    /* TRUE if we show pixmap while it renders */
  44. extern short        num_new_log_lines;        /* the number of stdout lines not yet in the log */
  45. extern CGrafPtr        image_port;                /* offscreen port which contains the image */
  46. extern WindowPtr    image_window;            /* the image window data structures */
  47. extern short        SCREEN_SIZE_X_MAX;
  48. extern short        SCREEN_SIZE_Y_MAX;
  49. extern char            sff_filename[200];        /* pathname of file to render */
  50. extern short        sff_file_vrefnum;        /* The volume refnum of the sff file directory */
  51. extern DialogPtr    options_dialog;            /* the options dialog */
  52. extern DialogPtr    preferences_dialog;        /* the preferences dialog */
  53. extern DialogPtr    status_dialog;            /* the status dialog */
  54. extern DialogPtr    animation_dialog;        /* the animation dialog */
  55. extern WindowPtr    log_window;                /* the log window */
  56. extern DialogPtr    about_dialog;            /* the about dialog */
  57. extern DialogPtr    abort_render_dialog;    /* the Abort Render dialog */
  58. extern DialogPtr    cancel_dialog;            /* the Cancel dialog */
  59. extern DialogPtr    error_dialog;            /* the Error dialog */
  60. extern DialogPtr    offer_to_abort_dialog;    /* the Offer to Abort dialog */
  61. extern DialogPtr    saving_frame_dialog;    /* the Saving Frame dialog */
  62. extern Boolean        allow_background_tasks;    /* TRUE if we handle events and give time to
  63.                                                 background processed while rendering */
  64. extern Boolean        show_image_rendering;    /* TRUE if we show the image in a window */
  65. extern Boolean        keep_image_in_memory;    /* TRUE if we keep a pixmap of the image in memory */
  66. extern Boolean        show_status_window_flag;/* TRUE if the status dialog is shown each render */
  67. extern Boolean        show_about_window_flag;    /* TRUE if the about window is shown at startup */
  68. extern Boolean        hide_options_window_flag;/* TRUE if the options dialog is hidden each render */
  69. extern long            time_between_events;    /* number of ticks between calls to WaitNextEvent */
  70. extern long            frames;                    /* The number of frames in the animation sequence */
  71. extern Boolean        find_folder_available;    /* TRUE if FindFolder is available */
  72. extern Boolean        starting_up;            /* TRUE if we're still starting up */
  73. extern Boolean        f8bit_QD_available;        /* TRUE if 8-bit QuickDraw is available */
  74. extern Boolean        quicktime_available;    /* TRUE if QuickTime is available */
  75.  
  76.  
  77. /* globals */
  78. fpos_t            current_stdout_read_pos;    /* position we're reading in stdout */
  79. fpos_t            current_stderr_read_pos;    /* position we're reading in stderr */
  80. FILE            *stdout_file;                /* file to which stdout is redirected */
  81. FILE            *stderr_file;                /* file to which stderr is redirected */
  82. short            blessed_folder_wd_id;        /* Working Directory refnum of blessed folder */
  83. short            temp_folder_wd_id;            /* Working Directory refnum of Temporary Items folder */
  84. short            rtrace_wd_id;                /* Working Directory refnum of RTrace folder */
  85. short            sff_file_wd_id;                /* Working Directory refnum of .sff file folder */
  86.  
  87. int                log_window_available=FALSE; /* Changed to TRUE after setup_log_window used to
  88.                                              *  tell DB macro defined in macerrors.h that we can 
  89.                                              *  write to the log window instead of the console.
  90.                                              */
  91.  
  92. char            rtrace_prefs_filename[] = "\pMacRTrace Preferences";
  93.  
  94. short                preferences_file_refnum;
  95. preferences_struct    **prefs_handle;
  96.  
  97.  
  98.  
  99.  
  100. /* Prototypes */
  101. Boolean open_sff_file(char *pathname);
  102. pascal Boolean filter_sff (fileParam *file_params);
  103. long get_num_objects_sff(char *filename);
  104. void write_rect(short refnum, Rect *rect);
  105. void write_long(short refnum, long number);
  106. void write_short(short refnum, short number);
  107. void write_char(short refnum, char number);
  108. void do_stdout_check(void);
  109. void save_pict_file(SFReply    *my_reply);
  110. void save_ppm_file(SFReply *my_reply);
  111. void save_quicktime_movie(SFReply *my_reply);
  112. void save_pict_files(SFReply *my_reply);
  113. void delete_pict_files(SFReply *my_reply);
  114. void stdout_to_log(void);
  115. void add_line_to_log_window (char *line);
  116. void preprocess_sff_file(long *num_lights, long *num_surfaces, long *num_objects);
  117. void count_polygon(FILE *sff_file, char *this_line, long *num_objects);
  118. void count_text3d(FILE *sff_file, char *this_line, long *num_objects);
  119. void place_window (WindowPtr window, Rect *bounds);
  120. void write_preferences(void);
  121. void get_preferences(void);
  122. void update_preferences_handle(void);
  123. void remember_window_position(WindowPtr window, Rect *dest_rect);
  124. void convert_ppm_to_pict(char *ppm_filename, Str255 pict_filename, short pict_vrefnum);
  125. void handle_io_error(short error);
  126. void setup_temp_folder(void);
  127. void delete_temp_files(Boolean movie_too);
  128. short make_working_directory(short vrefnum, long dir_id);
  129. void create_about_movie(void);
  130.  
  131.  
  132.  
  133. /*****************************************************************************\
  134. * procedure open_sff_file                                                     *
  135. *                                                                             *
  136. * Purpose: This procedure allows the user to select a .sff file using the     *
  137. *          standard Mac file dialog.                                          *
  138. *                                                                             *
  139. * Parameters: pathname contains pathname of selected file, if any.            *
  140. *             returns 0 of user cancels, 1 of not                             *
  141. *                                                                             *
  142. * Created by: Greg Ferrar                                                     *
  143. * Created on: August 21, 1992                                                 *
  144. * Modified:                                                                   *
  145. \*****************************************************************************/
  146.  
  147. Boolean open_sff_file(char *pathname)
  148. {
  149.  
  150.     SFTypeList    types;                /* permissible file types to open */
  151.     SFReply     sff_file_reply;        /* data structure for file info */
  152.     Point        where = {40, 40};    /* SF dialog location */
  153.  
  154.     types[0] = 'TEXT';
  155.  
  156.     /* Let the user choose an .sff input file.  */
  157.     SFGetFile (where, 0L, filter_sff, 1, types, 0L, &sff_file_reply);
  158.  
  159.     /* If the user cancelled, return 1 */
  160.     if (!sff_file_reply.good)
  161.         return 0;
  162.  
  163.     /* Set the default directory to the .sff directory */
  164.     sff_file_wd_id = sff_file_reply.vRefNum;
  165.     SetVol ((StringPtr) NULL, sff_file_wd_id);
  166.  
  167.     /* Get the filename of this .sff file */
  168.     strcpy (pathname, PtoCstr(sff_file_reply.fName));
  169.  
  170.     /* no problems */
  171.     return 1;
  172.     
  173. }    /* open_sff_file() */
  174.  
  175.  
  176.  
  177. /*****************************************************************************\
  178. * procedure filter_sff                                                        *
  179. *                                                                             *
  180. * Purpose: This procedure filters files in the standard file dialog so only   *
  181. *          those ending in .sff appear.                                       *
  182. *                                                                             *
  183. * Parameters: file_params contains a description of one file                  *
  184. *             returns FALSE if the file should be displayed.                  *
  185. *                                                                             *
  186. * Created by: Greg Ferrar                                                     *
  187. * Created on: August 21, 1992                                                 *
  188. * Modified:                                                                   *
  189. \*****************************************************************************/
  190.  
  191. pascal Boolean filter_sff (fileParam *file_params)
  192. {
  193.  
  194.     /* Get the filename address and length */
  195.     char *name = (char *) file_params->ioNamePtr;
  196.     int length = name[0];
  197.     
  198.     /* check that the last four characters are ".sff" */
  199.     if ((name[length - 3] == '.') &&
  200.         (name[length - 2] == 's') &&
  201.         (name[length - 1] == 'f') &&
  202.         (name[length] == 'f'))
  203.         return FALSE;
  204.     else return TRUE;
  205.  
  206. }    /* filter_sff() */
  207.  
  208.  
  209.  
  210. /*****************************************************************************\
  211. * procedure save_pict_file                                                    *
  212. *                                                                             *
  213. * Purpose: This procedure creates a pict file.  The PICT file is generated    *
  214. *          from the temporary .ppm file.                                      *
  215. *                                                                             *
  216. * Parameters: my_reply: the result of the SPutFile call                       *
  217. *                                                                             *
  218. * Created by: Greg Ferrar                                                     *
  219. * Created on: August 26, 1992                                                 *
  220. * Modified:                                                                   *
  221. *   WHO          WHEN             WHAT                                        *
  222. *   Greg Ferrar  9/9/92           moved guts to convert_ppm_to_pict           *
  223. \*****************************************************************************/
  224.  
  225. void save_pict_file(SFReply    *my_reply)
  226. {
  227.  
  228.     /* Convert ~rttemp.ppm into a PICT file */
  229.     convert_ppm_to_pict("~~rttemp.ppm", my_reply->fName, my_reply->vRefNum);
  230.  
  231. }    /* save_pict_file() */
  232.  
  233.  
  234.  
  235. /*****************************************************************************\
  236. * procedure convert_ppm_to_pict                                               *
  237. *                                                                             *
  238. * Purpose: This procedure converts a .ppm file to a PICT file.                *
  239. *            We are not going thru offscreen GWorlds but are trying to save    *
  240. *            memory by reading and compacting the .ppm file on the fly.        *
  241. * Note:    this code will work only for .ppm created by RTrace (see comment   *
  242. *            in code reading in .ppm header).                                  *
  243. *                                                                             *
  244. * Parameters: ppm_filename:  the filename of the ppm file to convert          *
  245. *             pict_filename: the filename to of the PICT file to create       *
  246. *             pict_vrefnum:  the vrefnum of the PICT file directory           *
  247. *                                                                             *
  248. * Created by: Greg Ferrar                                                     *
  249. * Created on: September 9, 1992                                               *
  250. * Modified:                                                                   *
  251. *   WHO          WHEN             WHAT                                        *
  252. *   Reid Judd  9/18/92            numerous changes for V2 packed pict files   *
  253. \*****************************************************************************/
  254.  
  255. void convert_ppm_to_pict(char *ppm_filename, Str255 pict_filename, short pict_vrefnum)
  256. {
  257.  
  258.     EventRecord        event;
  259.     short            pict_file_refnum;            /* refnum of output file */
  260.     short            error;
  261.     char            *zeros_buffer;                /* pointer to buffer of zeros */
  262.     long            scan_line_buffer_size;
  263.     long            num_bytes;
  264.     short             row_bytes;                    /* number of bytes per row */
  265.     long            pict_file_length;
  266.     Rect            pict_frame;
  267.     FILE            *source;
  268.     short            lines_found;
  269.     char            this_char;
  270.     Rect            huge_rect = {-32767, -32767, 32767, 32767};
  271.     long            component_buffer_size;
  272.     unsigned char    **unpacked_buffer_handle;
  273.     unsigned char    **packed_buffer_handle;
  274.     unsigned char    **red_buffer_handle;
  275.     unsigned char    **green_buffer_handle;
  276.     unsigned char    **blue_buffer_handle;
  277.     unsigned char    *unpacked_buffer;
  278.     unsigned char    *packed_buffer;
  279.     unsigned char    *source_buffer;
  280.     unsigned char    *dest_buffer;
  281.     unsigned char    *red_buffer;
  282.     unsigned char    *green_buffer;
  283.     unsigned char    *blue_buffer;
  284.     long            i, j;
  285.     long            read_component_bytes;
  286.  
  287.     /* Create and open the ouput file for writing */
  288.     FSDelete (pict_filename, pict_vrefnum);
  289.     error = Create (pict_filename, pict_vrefnum, 'ttxt', 'PICT');
  290.     if (error) abortive_error(error);
  291.  
  292.     error = FSOpen (pict_filename, pict_vrefnum, &pict_file_refnum);
  293.     if (error) abortive_error(error);
  294.  
  295.     /* Find the image size for later use */
  296.     pict_frame.left = pict_frame.top = 0;
  297.     pict_frame.bottom = SCREEN_SIZE_Y_MAX - 1;
  298.     pict_frame.right = SCREEN_SIZE_X_MAX - 1;
  299.  
  300.     /* Find number of bytes per row */
  301.     row_bytes = 4*(SCREEN_SIZE_X_MAX - 1);
  302.  
  303.     /* Create a 512 byte buffer of zeros for write_zeros */
  304.     zeros_buffer = NewPtrClear (512);
  305.     if (error = MemError()) abortive_error(error);
  306.     num_bytes = 512;
  307.     error = FSWrite (pict_file_refnum, &num_bytes, zeros_buffer);
  308.     if (error) abortive_error(error);
  309.     DisposPtr (zeros_buffer);
  310.  
  311.     /* Write all the header data.  This is taken straight from
  312.         IM VI, 17-24, 2nd edition june'91. */
  313.     write_short(pict_file_refnum, 0);            /* Write zero picSize (fill in later) */
  314.     write_rect (pict_file_refnum, &pict_frame);    /* Write the picture Frame (8 bytes) */
  315.     write_long(pict_file_refnum, 0x001102FF);    /* Write the version information */
  316.     write_short(pict_file_refnum, 0x0C00);        /* Write a Header opcode */
  317.  
  318.     write_short(pict_file_refnum, 0xFFFE);        /* Write -2 to indicate v2 picture */
  319.     write_short(pict_file_refnum, 0x0000);        /* Write 0 to reserved value */
  320.     write_long(pict_file_refnum, (0x00480000) );  /* Native hRes (72dpi) */
  321.     write_long(pict_file_refnum, (0x00480000) );  /* Native vRes (72dpi) */
  322.     write_rect (pict_file_refnum, &pict_frame);    /* Write srcRect (8 bytes) */
  323.     write_long(pict_file_refnum, 0);            /* Write a 0 to the reserved area */
  324.     write_short(pict_file_refnum, 0x001E);        /* Write DefHilite opcode */
  325.     write_short(pict_file_refnum, 0x0001);        /* Write Clip opcode */
  326.     write_short(pict_file_refnum, 0x000A);
  327.     write_rect (pict_file_refnum, &huge_rect);    /* define clipping to be all QDSpace */
  328.     write_short(pict_file_refnum, 0x009A);        /* Write a DirectBitsRect opcode */
  329.     write_long (pict_file_refnum, 0x000000FF);    /* Write to baseAddr field */
  330.     write_short(pict_file_refnum, row_bytes | 0x8000);  /* Write bytes per row */
  331.  
  332.     write_rect (pict_file_refnum, &pict_frame);    /* Write the source rectangle */
  333.     write_short(pict_file_refnum, 0);            /* Write pixel map version */
  334.     write_short(pict_file_refnum, 4);            /* Write packing type (RLE) */
  335.     write_long(pict_file_refnum, 0);            /* Write packed data size (0 for RLE) */
  336.     write_long(pict_file_refnum, 0x00480000);    /* Write a horizontal resolution (72 dpi) */
  337.     write_long(pict_file_refnum, 0x00480000);    /* Write a vertical resolution (72 dpi) */
  338.     write_short(pict_file_refnum, RGBDirect);    /* Write direct pixel mode */
  339.     write_short(pict_file_refnum, 32);            /* Write bits per pixel */
  340.     write_short(pict_file_refnum, 3);            /* Write color components per pixel */
  341.     write_short(pict_file_refnum, 8);            /* Write color component size */
  342.     write_long(pict_file_refnum, 0);            /* Write 0 to plane longword */
  343.     write_long(pict_file_refnum, 0x645970);        /* Write 0x645970 because it works! */
  344.     write_short(pict_file_refnum, 0);            /* Write 0 to color table flags word */
  345.     write_short(pict_file_refnum, 0);            /* Write 0 to color table size word */
  346.     write_rect (pict_file_refnum, &pict_frame);    /* Write the source rectangle */
  347.     write_rect (pict_file_refnum, &pict_frame);    /* Write the source rectangle */
  348.     write_short(pict_file_refnum, srcCopy);        /* Write transfer mode */
  349.  
  350.     /* Open the temporary .ppm file (in the Temporary Items directory),
  351.         and transfer the picture data to the PICT file. */
  352.     error = SetVol( (StringPtr) NULL, temp_folder_wd_id);
  353.     if (error) abortive_error(error);
  354.     source = fopen (ppm_filename, "rb");    /* open to read binary */
  355.     
  356.     /* Ignore the header.  We know the header is over when we find the 4th newline */
  357.     lines_found = 0;
  358.     while (lines_found < 4)
  359.         {
  360.         fread (&this_char, 1, 1, source);
  361.         if (this_char == '\n') lines_found++;
  362.         }
  363.     
  364.     /* Create buffers for the ppm scan line, for each color component, and for
  365.         the RLE-compressed component */
  366.     scan_line_buffer_size = 3*(SCREEN_SIZE_X_MAX-1);
  367.     component_buffer_size = SCREEN_SIZE_X_MAX-1;
  368.  
  369.     /* Allocate ppm scan line buffer */
  370.     unpacked_buffer_handle = (unsigned char **) NewHandle(scan_line_buffer_size);
  371.     if (error = MemError()) abortive_error(error);
  372.     HLock(unpacked_buffer_handle);
  373.     unpacked_buffer = *unpacked_buffer_handle;
  374.  
  375.     /* Allocate RLE-compressed component buffer */
  376.     packed_buffer_handle = (unsigned char **) NewHandle(scan_line_buffer_size);
  377.     if (error = MemError()) abortive_error(error);
  378.     HLock(packed_buffer_handle);
  379.     packed_buffer = *packed_buffer_handle;
  380.     
  381.     /* Allocate red component buffer */
  382.     red_buffer_handle = (unsigned char **) NewHandle(component_buffer_size);
  383.     if (error = MemError()) abortive_error(error);
  384.     HLock(red_buffer_handle);
  385.     red_buffer = *red_buffer_handle;
  386.  
  387.     /* Allocate green component buffer */
  388.     green_buffer_handle = (unsigned char **) NewHandle(component_buffer_size);
  389.     if (error = MemError()) abortive_error(error);
  390.     HLock(green_buffer_handle);
  391.     green_buffer = *green_buffer_handle;
  392.  
  393.     /* Allocate blue component buffer */
  394.     blue_buffer_handle = (unsigned char **) NewHandle(component_buffer_size);
  395.     if (error = MemError()) abortive_error(error);
  396.     HLock(blue_buffer_handle);
  397.     blue_buffer = *blue_buffer_handle;
  398.  
  399.      /* copy the file one line at a time, compressing as we go */
  400.     while (1)
  401.         {
  402.         
  403.         /* Give background processes a little time, but don't accept any events */
  404.         WaitNextEvent (0, &event, 0, (RgnHandle) 0L);
  405.     
  406.         /* Read a line */
  407.         num_bytes = fread (unpacked_buffer, 1, scan_line_buffer_size, source);
  408.         
  409.         /* If there's no more, we're done */
  410.         if (feof(source))
  411.             break;
  412.         
  413.         /* Extract the components */
  414.         for (i = 0, j = 0; i < component_buffer_size; i++, j += 3)
  415.             {
  416.             red_buffer[i] = unpacked_buffer[j];
  417.             green_buffer[i] = unpacked_buffer[j+1];
  418.             blue_buffer[i] = unpacked_buffer[j+2];
  419.             }
  420.         
  421.         /* compress the red component */
  422.         source_buffer = red_buffer;
  423.         dest_buffer = packed_buffer;
  424.         PackBits(&source_buffer, &dest_buffer, component_buffer_size);
  425.         
  426.         /* compress the green component */
  427.         source_buffer = green_buffer;
  428.         PackBits(&source_buffer, &dest_buffer, component_buffer_size);
  429.         
  430.         /* compress the blue component */
  431.         source_buffer = blue_buffer;
  432.         PackBits(&source_buffer, &dest_buffer, component_buffer_size);
  433.         
  434.         /* Write the compressed line size (a byte if the number of bytes in
  435.             scan line is < 250, or a word otherwise */
  436.         read_component_bytes = dest_buffer - packed_buffer;
  437.  
  438.         if (row_bytes > 250) 
  439.             write_short(pict_file_refnum, read_component_bytes);
  440.         else
  441.             write_char(pict_file_refnum, read_component_bytes);
  442.           
  443.         /* write the compressed scan line */
  444.         error = FSWrite (pict_file_refnum, &read_component_bytes, packed_buffer);
  445.         if (error) abortive_error(error);
  446.         }
  447.  
  448.     /* Free up the buffers */
  449.     DisposHandle(unpacked_buffer_handle);
  450.     DisposHandle(packed_buffer_handle);
  451.     DisposHandle(red_buffer_handle);
  452.     DisposHandle(green_buffer_handle);
  453.     DisposHandle(blue_buffer_handle);
  454.  
  455.     /* Write a EndOfPicture opcode, word-aligned */
  456.     error = GetFPos (pict_file_refnum, &pict_file_length);
  457.     if (error) abortive_error(error);
  458.     if (pict_file_length & 1)
  459.         {
  460.         write_char(pict_file_refnum, 0);    /* pad with zero byte */        
  461.         pict_file_length++;
  462.         }        
  463.     write_short(pict_file_refnum, 0x00FF);
  464.     
  465.     /* Write the PICT length, back at the beginning */
  466.     error = SetFPos (pict_file_refnum, fsFromStart, 512);
  467.     if (error) abortive_error(error);
  468.     write_short(pict_file_refnum, (short) (pict_file_length - 512 + 2) );
  469.     
  470.     /* Close the .ppm file */
  471.     fclose(source);
  472.     
  473.     /* Close the output file */
  474.     error = FSClose (pict_file_refnum);
  475.     if (error) abortive_error(error);
  476.  
  477. }    /* save_pict_file() */
  478.  
  479.  
  480.  
  481. void write_short(short refnum, short number)
  482. {
  483.     long    num_bytes = 2;
  484.     short    error;
  485.     
  486.     error = FSWrite (refnum, &num_bytes, &number);
  487.     if (error) abortive_error(error);
  488. }
  489.  
  490.  
  491. void write_char(short refnum, char number)
  492. {
  493.     long num_bytes = 1;
  494.     short    error;
  495.     
  496.     error = FSWrite (refnum, &num_bytes, &number);
  497.     if (error) abortive_error(error);
  498.  
  499. }
  500.  
  501.  
  502. void write_long(short refnum, long number)
  503. {
  504.     long num_bytes = 4;
  505.     short    error;
  506.     
  507.     error = FSWrite (refnum, &num_bytes, &number);
  508.     if (error) abortive_error(error);
  509. }
  510.  
  511.  
  512. void write_rect(short refnum, Rect *rect)
  513. {
  514.     long num_bytes = 8;
  515.     short    error;
  516.     
  517.     error = FSWrite (refnum, &num_bytes, rect);
  518.     if (error) abortive_error(error);
  519. }
  520.  
  521.  
  522.  
  523. /*****************************************************************************\
  524. * procedure save_ppm_file                                                     *
  525. *                                                                             *
  526. * Purpose: This procedure creates a ppm file.  It does this by copying the    *
  527. *          temporary ppm file.                                                *
  528. *                                                                             *
  529. * Parameters: my_reply: the result of the SPutFile call                       *
  530. *                                                                             *
  531. * Created by: Greg Ferrar                                                     *
  532. * Created on: August 26, 1992                                                 *
  533. * Modified:                                                                   *
  534. \*****************************************************************************/
  535.  
  536. void save_ppm_file(SFReply *my_reply)
  537. {
  538.  
  539.     FILE    *source;
  540.     char    *buffer;            /* buffer for file data */
  541.     long    copy_buffer_size;
  542.     short    ppm_file_refnum;
  543.     short    error;
  544.     long    count;
  545.  
  546.     /* Open the input file for reading (in the Temporary Items directory) */
  547.     SetVol( (StringPtr) NULL, temp_folder_wd_id);
  548.     source = fopen ("~~rttemp.ppm", "rb");    /* open to read binary */
  549.     
  550.     /* Create and open the ouput file for writing */
  551.     error = FSDelete (my_reply->fName, my_reply->vRefNum);
  552.     error = Create (my_reply->fName, my_reply->vRefNum, 'RTRC', '.ppm');
  553.     if (error) abortive_error(error);
  554.     error = FSOpen (my_reply->fName, my_reply->vRefNum, &ppm_file_refnum);
  555.     if (error) abortive_error(error);
  556.     
  557.     /* Create the largest possible file buffer */
  558.     copy_buffer_size = MaxBlock ();
  559.     buffer = NewPtr(copy_buffer_size);
  560.     
  561.     /* copy data from source to dest in blocks of copy_buffer_size */
  562.     while (!feof(source))
  563.         {
  564.         count = fread (buffer, 1, copy_buffer_size, source);
  565.         FSWrite (ppm_file_refnum, &count, buffer);
  566.         if (error) abortive_error(error);
  567.         }
  568.         
  569.     /* Free up the file buffer */
  570.     DisposPtr(buffer);
  571.  
  572.     /* Close the input file */
  573.     fclose(source);
  574.     
  575.     /* Close the output file */
  576.     FSClose (ppm_file_refnum);
  577.     if (error) abortive_error(error);
  578.     
  579. }    /* save_ppm_file() */
  580.  
  581.  
  582.  
  583. /*****************************************************************************\
  584. * procedure save_pict_files                                                   *
  585. *                                                                             *
  586. * Purpose: This procedure save the animation sequence as a series of PICT     *
  587. *          files.  It does this by copying the PPM files.                     *
  588. *                                                                             *
  589. * Parameters: my_reply: the result of the SPutFile call                       *
  590. *                                                                             *
  591. * Created by: Greg Ferrar                                                     *
  592. * Created on: September 9, 1992                                               *
  593. * Modified:                                                                   *
  594. \*****************************************************************************/
  595.  
  596. void save_pict_files(SFReply *my_reply)
  597. {
  598.  
  599.     long    i;
  600.     Str255    pict_filename;
  601.     char    ppm_filename[255];
  602.     
  603.     /* Convert the chosen filename for the PICT files to a C string */
  604.     PtoCstr(my_reply->fName);
  605.  
  606.     /* Show the saving frame dialog */
  607.     ShowWindow(saving_frame_dialog);
  608.     SelectWindow(saving_frame_dialog);
  609.  
  610.     /* Loop through all the "~~rttempn.ppm" files, and convert each one to
  611.         a PICT file */
  612.     for    (i = 1; i <= frames; i++)
  613.         {
  614.  
  615.         /* Update the text in the saving frame dialog */
  616.         NumToString(i, pict_filename);
  617.         ParamText(pict_filename, 0, 0, 0);
  618.         DrawDialog(saving_frame_dialog);
  619.  
  620.         /* Find the filename of this ppm file */
  621.         sprintf(ppm_filename, "~~rttemp%ld.ppm", i);
  622.         
  623.         /* Find the filename of this PICT file */
  624.         sprintf((char *) pict_filename, "%s.%ld", my_reply->fName, i);
  625.         CtoPstr(pict_filename);
  626.     
  627.         /* Convert the ppm into a PICT file */
  628.         convert_ppm_to_pict(ppm_filename, pict_filename, my_reply->vRefNum);
  629.                 
  630.         }
  631.  
  632.     /* Convert the filename back to a P string */
  633.     CtoPstr(my_reply->fName);
  634.  
  635.     /* Hide the saving frame dialog */
  636.     HideWindow(saving_frame_dialog);
  637.  
  638. }    /* save_pict_files() */
  639.  
  640. /*****************************************************************************\
  641. * procedure delete_pict_files                                                 *
  642. *                                                                             *
  643. * Purpose: This procedure removes the sequence of PICT files that were used   *
  644. *          to form the QuickTime movie and are therefore, no longer useful.   *
  645. *                                                                              *
  646. *           However, we may replace this soon with a new procedure that will   *
  647. *           create each individual pict file, append it to a movie, and then   *
  648. *          delete it on the fly.                                              *
  649. *                                                                             *
  650. * Parameters: my_reply: the result of the SPutFile call                       *
  651. *                                                                             *
  652. * Created by: Reid Judd                                                       *
  653. * Created on: September 28, 1992                                              *
  654. * Modified:                                                                   *
  655. \*****************************************************************************/
  656.  
  657. void delete_pict_files(SFReply *my_reply)
  658. {
  659.  
  660.     long    i;
  661.     Str255    pict_filename;
  662.     char    ppm_filename[255];
  663.     short   error;
  664.     
  665.     /* Convert the chosen filename for the PICT files to a C string */
  666.     PtoCstr(my_reply->fName);
  667.  
  668.     /* Loop through all the pict files, and delete each one */
  669.      for    (i = 1; i <= frames; i++)
  670.         {
  671.         /* Find the filename of this PICT file */
  672.         sprintf((char *) pict_filename, "%s.%ld", my_reply->fName, i);
  673.         CtoPstr(pict_filename);
  674.         error = FSDelete ( pict_filename, my_reply->vRefNum); 
  675.             
  676.         if (error) abortive_error(error);
  677.  
  678.         }
  679.  
  680.     /* Convert the filename back to a P string */
  681.     CtoPstr(my_reply->fName);
  682.  
  683. }    /* delete_pict_files() */
  684.  
  685.  
  686.  
  687. /*****************************************************************************\
  688. * procedure save_quicktime_movie                                              *
  689. *                                                                             *
  690. * Purpose: This procedure saves the animation sequence as a quicktime movie.  *
  691. *                                                                             *
  692. * Parameters: my_reply: the result of the SPutFile call                       *
  693. *                                                                             *
  694. * Created by: Reid Judd                                                       *
  695. * Created on: September 21, 1992                                              *
  696. * Modified:                                                                   *
  697. \*****************************************************************************/
  698.  
  699. void save_quicktime_movie(SFReply *my_reply)
  700. {
  701.   save_pict_files( my_reply );
  702.  
  703.   convert_picts_to_movie( my_reply );
  704.   
  705.   /* Now delete the pict files that were created. */
  706.   delete_pict_files( my_reply );
  707.     
  708. }    /* save_quicktime_movie() */
  709.  
  710.  
  711.  
  712. /*****************************************************************************\
  713. * procedure stdout_to_log                                                     *
  714. *                                                                             *
  715. * Purpose: This procedure transfers a line from stdout to the log file.       *
  716. *                                                                             *
  717. * Created by: Greg Ferrar                                                     *
  718. * Created on: August 26, 1992                                                 *
  719. * Modified:                                                                   *
  720. \*****************************************************************************/
  721.  
  722. void stdout_to_log(void)
  723. {
  724.  
  725.     char    this_line[100];
  726.     
  727.     /* Go to the last place we read from */
  728.     fsetpos(stdout_file, ¤t_stdout_read_pos);
  729.  
  730.     while (1)
  731.         {
  732.         
  733.         /* Try to read a string */
  734.         fgets(this_line, 10000, stdout_file);
  735.     
  736.         /* If we found the end of the file, that's it */
  737.         if (feof(stdout_file)) break;
  738.  
  739.         /* make the newline a return, */
  740.         this_line[strlen(this_line) - 1] = '\r';
  741.         
  742.         /* and add it to the log window */
  743.         add_line_to_log_window (this_line);
  744.         
  745.         /* We have one less log line to worry about */
  746.         num_new_log_lines--;
  747.         
  748.         /* Remember where to read from next time */
  749.         fgetpos(stdout_file, ¤t_stdout_read_pos);
  750.  
  751.         }
  752.  
  753. }
  754.  
  755.  
  756.  
  757. /*****************************************************************************\
  758. * procedure setup_temp_folder                                                 *
  759. *                                                                             *
  760. * Purpose: This procedure finds the vrefnum of the Temporary Items folder so  *
  761. *          we can store our temporary files there.                            *
  762. *                                                                             *
  763. * Created by: Greg Ferrar                                                     *
  764. * Created on: September 12, 1992                                              *
  765. * Modified:                                                                   *
  766. *   WHO          WHEN             WHAT                                        *
  767. \*****************************************************************************/
  768.  
  769. void setup_temp_folder(void)
  770. {
  771.  
  772.     short     error;
  773.     short     temp_folder_vrefnum;
  774.     long    temp_folder_dirid;
  775.  
  776.     /* If FindFolder doesn't exist, we'll just use the RTrace directory */
  777.     if (!find_folder_available)
  778.         temp_folder_wd_id = rtrace_wd_id;
  779.  
  780.     else
  781.         {
  782.         error = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
  783.                             &temp_folder_vrefnum, &temp_folder_dirid);
  784.         if (error) terminal_startup_error(error);
  785.         
  786.         /* Make it into a working directory */
  787.         temp_folder_wd_id = make_working_directory(temp_folder_vrefnum, temp_folder_dirid);
  788.         }
  789.  
  790.     /* Clear out any of our temporary files in the Temporary Items Folder, if somehow
  791.         they were left there last time the program ran */
  792.     delete_temp_files(TRUE);
  793.  
  794.     /* Create the About... movie, if we have QuickTime */
  795.     if (quicktime_available)
  796.         create_about_movie();
  797.     
  798. }    /* create_about_movie() */
  799.  
  800.  
  801.  
  802. /*****************************************************************************\
  803. * procedure create_about_movie                                                *
  804. *                                                                             *
  805. * Purpose: This procedure creates the movie which will rotate the RTrace in   *
  806. *          the About... dialog.                                               *
  807. *                                                                             *
  808. * Created by: Greg Ferrar                                                     *
  809. * Created on: September 22, 1992                                              *
  810. * Modified:                                                                   *
  811. *   WHO          WHEN             WHAT                                        *
  812. \*****************************************************************************/
  813.  
  814. void create_about_movie(void)
  815. {
  816.  
  817.     long    proc_id;
  818.     FSSpec    fsspec;
  819.     short    error;
  820.     long    size;
  821.     Handle    handle;
  822.     short    frefnum;
  823.     
  824.     /* Create the FSSpec for the movie file */
  825.     error = GetWDInfo (temp_folder_wd_id, &(fsspec.vRefNum), &(fsspec.parID), &proc_id);
  826.     if (error) terminal_error(error);
  827.     strcpy ((char *) fsspec.name, (char *) "~~rtrace_movie");
  828.     CtoPstr ((char *) fsspec.name);
  829.  
  830.     /* Create the movie file */
  831.     error = FSpCreate(&fsspec, 'TVOD', 'MooV', smSystemScript);
  832.     if (error) terminal_error(error);
  833.     
  834.     /* Write the movie file resource fork */
  835.     error = FSpOpenRF(&fsspec, fsCurPerm, &frefnum);
  836.     if (error) terminal_error(error);
  837.     handle = GetResource('movf', 128);
  838.     size = GetHandleSize(handle);
  839.     HLock(handle);
  840.     error = FSWrite (frefnum, &size, *handle);
  841.     if (error) terminal_error(error);
  842.     HUnlock(handle);
  843.     error = FSClose(frefnum);
  844.     if (error) terminal_error(error);
  845.     
  846.     /* Write the movie file data fork */
  847.     error = FSpOpenDF(&fsspec, fsCurPerm, &frefnum);
  848.     if (error) terminal_error(error);
  849.     handle = GetResource('movf', 129);
  850.     size = GetHandleSize(handle);
  851.     HLock(handle);
  852.     error = FSWrite (frefnum, &size, *handle);
  853.     if (error) terminal_error(error);
  854.     HUnlock(handle);
  855.     error = FSClose(frefnum);
  856.     if (error) terminal_error(error);
  857.  
  858. }    /* create_about_movie() */
  859.  
  860.  
  861.  
  862. /*****************************************************************************\
  863. * procedure delete_temp_files                                                 *
  864. *                                                                             *
  865. * Purpose: This procedure deletes all temporary files from the Temporary      *
  866. *          Items directory.                                                   *
  867. *                                                                             *
  868. * Parameters: movie_too: TRUE if the About... movie should also be deleted.   *
  869. *                                                                             *
  870. * Created by: Greg Ferrar                                                     *
  871. * Created on: September 12, 1992                                              *
  872. * Modified:                                                                   *
  873. *   WHO          WHEN             WHAT                                        *
  874. \*****************************************************************************/
  875.  
  876. void delete_temp_files(Boolean movie_too)
  877. {
  878.  
  879.     short        index = 1;
  880.     short        error;
  881.     HFileInfo    CPB;
  882.     char        filename[256];
  883.     long        dirid;
  884.     long        proc_id;
  885.  
  886.     /* Set up filename buffer */
  887.     CPB.ioNamePtr = (unsigned char *) filename;
  888.  
  889.     /* Find the volume and directory id of the Temporary directory */
  890.     error = GetWDInfo (temp_folder_wd_id, &(CPB.ioVRefNum), &dirid, &proc_id);
  891.     if (error) terminal_startup_error(error);
  892.  
  893.     /* Scan through all files in the directory */
  894.     do
  895.         {
  896.         
  897.         /* Set index to point to current file */
  898.         CPB.ioFDirIndex = index;    
  899.  
  900.         /* Set directory to search */
  901.         CPB.ioDirID = dirid;
  902.         
  903.         /* Get the info on this file */
  904.         error = PBGetCatInfo(&CPB, FALSE);
  905.         if (error) continue;
  906.     
  907.         /* Convert filename to a C string */
  908.         PtoCstr(filename);
  909.  
  910.         /* Is this the movie file, and if so, are we supposed to delete it? */
  911.         if ( (movie_too && !strcmp(filename, "rtrace_movie"))
  912.         
  913.         /* Or is it a temporary image file? */
  914.             || ((filename[0] == '~') && (filename[1] == '~')) )
  915.             
  916.             /* It's our file-- delete it */
  917.             {
  918.             CtoPstr(filename);
  919.             error = FSDelete (CPB.ioNamePtr, temp_folder_wd_id);
  920.             if (error) terminal_startup_error(error);
  921.             }
  922.         
  923.         /* Go to next file */
  924.         else
  925.             index++;
  926.         
  927.         }
  928.     while (!error);
  929.  
  930. }    /* delete_temp_files() */
  931.  
  932.  
  933.  
  934. /*****************************************************************************\
  935. * procedure preprocess_sff_file                                               *
  936. *                                                                             *
  937. * Purpose: This procedure quickly scans through a .sff file, grabbing the     *
  938. *          most important information, and ignoring the actual scene          *
  939. *          description.                                                       *
  940. *                                                                             *
  941. * Parameters: num_lights: receives the number of lights.                      *
  942. *             num_surfaces: receives the number of surfaces.                  *
  943. *             num_objects:  receives the number of objects.                   *
  944. *             also sets globals look, eye, up, view_angle_x, view_angle_y     *
  945. *                                                                             *
  946. * Created by: Greg Ferrar                                                     *
  947. * Created on: September 3, 1992                                               *
  948. * Modified:                                                                   *
  949. \*****************************************************************************/
  950.  
  951. void preprocess_sff_file(long *num_lights, long *num_surfaces, long *num_objects)
  952. {
  953.  
  954.     short    i;
  955.     char    this_line[200];
  956.     FILE    *scene;
  957.     Boolean    is_polygon;
  958.     double    value;
  959.     
  960.     /* Initialize the number of lights, surfaces, and objects to zero */
  961.     *num_lights = *num_surfaces = *num_objects = 0;
  962.  
  963.     /* Open the sff file for reading */
  964.     scene = fopen(sff_filename, "r");
  965.  
  966.     /* read the eye point */
  967.     ADVANCE(scene);
  968.     get_valid(scene, &value, X_MIN, X_MAX, "EYE POINT X");
  969.     eye.x = value;
  970.     get_valid(scene, &value, Y_MIN, Y_MAX, "EYE POINT Y");
  971.     eye.y = value;
  972.     get_valid(scene, &value, Z_MIN, Z_MAX, "EYE POINT Z");
  973.     eye.z = value;
  974.     
  975.     /* read the look point */
  976.     ADVANCE(scene);
  977.     get_valid(scene, &value, X_MIN, X_MAX, "LOOK POINT X");
  978.     look.x = value;
  979.     get_valid(scene, &value, Y_MIN, Y_MAX, "LOOK POINT Y");
  980.     look.y = value;
  981.     get_valid(scene, &value, Z_MIN, Z_MAX, "LOOK POINT Z");
  982.     look.z = value;
  983.  
  984.     /* Compute gaze */
  985.     ADVANCE(scene);
  986.     gaze.x = look.x - eye.x;
  987.     gaze.y = look.y - eye.y;
  988.     gaze.z = look.z - eye.z;
  989.     gaze_distance = LENGTH(gaze);
  990.  
  991.     /* If look point is on top of eye, point, gaze is null-- error */
  992.     if (gaze_distance < ROUNDOFF)
  993.         runtime_abort("EYE POINT equal to LOOK POINT");
  994.  
  995.     /* No problem */
  996.     NORMALIZE(gaze);
  997.  
  998.     /* Get up vector */
  999.     get_valid(scene, &value, X_MIN, X_MAX, "UP VECTOR X");
  1000.     up.x = value;
  1001.     get_valid(scene, &value, Y_MIN, Y_MAX, "UP VECTOR Y");
  1002.     up.y = value;
  1003.     get_valid(scene, &value, Z_MIN, Z_MAX, "UP VECTOR Z");
  1004.     up.z = value;
  1005.  
  1006.     /* if up vector is too null, error */
  1007.     if (LENGTH(up) < ROUNDOFF)
  1008.         runtime_abort("no UP VECTOR");
  1009.  
  1010.     /* No problem */
  1011.     NORMALIZE(up);
  1012.  
  1013.     /* Check for bad up vector */
  1014.     if (ABS(DOT_PRODUCT(gaze, up)) > COS(ANGLE_MIN))
  1015.         runtime_abort("bad UP VECTOR");
  1016.  
  1017.     /* Get view angles */
  1018.     ADVANCE(scene);
  1019.     get_valid(scene, &value, 0.5, 89.5, "HORIZONTAL VIEW Angle");   /* Degrees */
  1020.     view_angle_x = DEGREE_TO_RADIAN(value);
  1021.     get_valid(scene, &value, 0.5, 89.5, "VERTICAL VIEW Angle");     /* Degrees */
  1022.     view_angle_y = DEGREE_TO_RADIAN(value);
  1023.  
  1024.     /* Ignore the colors and the lights comment */
  1025.     for (i = 1; i <= 6; i++)
  1026.         fgets(this_line, 10000, scene);
  1027.         
  1028.     /* Count the number of lights */
  1029.     while (this_line [0] != '\n')
  1030.         {
  1031.         (*num_lights)++;
  1032.         fgets(this_line, 10000, scene);
  1033.         }
  1034.  
  1035.     /* Read the Surfaces comment, and the first surface description */
  1036.     fgets(this_line, 10000, scene);
  1037.     fgets(this_line, 10000, scene);
  1038.  
  1039.     /* Count the number of surfaces */
  1040.     while (this_line [0] != '\n')
  1041.         {
  1042.         (*num_surfaces)++;
  1043.         fgets(this_line, 10000, scene);
  1044.         }
  1045.  
  1046.     /* Read the Objects comment, and the first object description line */
  1047.     fgets(this_line, 10000, scene);
  1048.     fgets(this_line, 10000, scene);
  1049.  
  1050.     /* Count the number of objects */
  1051.     while (this_line [0] != '\n')
  1052.         {
  1053.         /* If this is an object which can have a descriptor file,
  1054.             and if the file is imbedded here, skip it */
  1055.         if (this_line[1] == ' ')
  1056.  
  1057.             switch (this_line[0])
  1058.                 {
  1059.                 case '5':    /* polygon */
  1060.                 case '3':    /* patch */
  1061.                 case '6':    /* triangle */
  1062.                     
  1063.                     /* count the number of objects in this polygon, patch, or triangle */
  1064.                     count_polygon(scene, this_line, num_objects);
  1065.                 
  1066.                     break;
  1067.                 
  1068.                 case '7':    /* 3D text */
  1069.                     
  1070.                     /* count the number of objects in this 3D text object */
  1071.                     count_text3d(scene, this_line, num_objects);
  1072.                     
  1073.                     break;
  1074.  
  1075.                 default:
  1076.                     
  1077.                     /* It's a simple object */
  1078.                     (*num_objects)++;
  1079.         
  1080.                 
  1081.                 }
  1082.  
  1083.         /* Get next object description */
  1084.         fgets(this_line, 10000, scene);
  1085.  
  1086.         }
  1087.  
  1088. }    /* preprocess_sff_file() */
  1089.  
  1090.  
  1091.  
  1092. /*****************************************************************************\
  1093. * procedure count_polygon                                                     *
  1094. *                                                                             *
  1095. * Purpose: This procedure counts the number of objects in a polygon,          *
  1096. *          triangle, or patch file.                                           *
  1097. *                                                                             *
  1098. * Parameters: sff_file: the sff file we're preprocessing.                     *
  1099. *             this_line: the polygon/triangle/patch descriptor line           *
  1100. *             num_objects: the number of objects counted so far.              *
  1101. *                                                                             *
  1102. * Created by: Greg Ferrar                                                     *
  1103. * Created on: September 7, 1992                                               *
  1104. * Modified:                                                                   *
  1105. \*****************************************************************************/
  1106.  
  1107. void count_polygon(FILE *sff_file, char *this_line, long *num_objects)
  1108. {
  1109.  
  1110.     FILE    *sub_file;
  1111.     char    *subfilename;
  1112.  
  1113.     /* Decide whether to read from this file or from another one */
  1114.     if (strstr(this_line, "-"))
  1115.     
  1116.         /* Use this file as the file */
  1117.         sub_file = sff_file;
  1118.     
  1119.     else    /* description is in another file */
  1120.         {
  1121.         
  1122.         /* get the filename to use */
  1123.         subfilename = (strrchr(this_line, ' ') + 1);
  1124.         
  1125.         /* Open the file */
  1126.         sub_file = fopen (subfilename, "r");
  1127.  
  1128.         }
  1129.     
  1130.     /* Ignore the object descriptor line */
  1131.     fgets(this_line, 10000, sub_file);
  1132.     
  1133.     /* Count the number of objects here */
  1134.     while (this_line [0] != '\n')
  1135.         {
  1136.         (*num_objects)++;
  1137.         fgets(this_line, 10000, sub_file);
  1138.         }
  1139.     
  1140.     /* If this was a separate file, we're done */
  1141.     if (sff_file != sub_file)
  1142.         fclose (sub_file);
  1143.  
  1144.     else    /* skip the rest */
  1145.         {
  1146.         
  1147.         /* Read the blank line */
  1148.         fgets(this_line, 10000, sub_file);
  1149.     
  1150.         /* Skip the vertex info (read until the first blank line) */
  1151.         while (!feof(sub_file) && (this_line [0] != '\n'))
  1152.             fgets(this_line, 10000, sub_file);
  1153.         
  1154.         }
  1155.  
  1156. }    /* count_polygon() */
  1157.  
  1158.  
  1159.  
  1160. /*****************************************************************************\
  1161. * procedure count_text3d                                                      *
  1162. *                                                                             *
  1163. * Purpose: This procedure counts the number of objects in a 3D text object.   *
  1164. *                                                                             *
  1165. * Parameters: sff_file: the sff file we're preprocessing.                     *
  1166. *             this_line: the text object descriptor line                      *
  1167. *             num_objects: the number of objects counted so far.              *
  1168. *                                                                             *
  1169. * Created by: Greg Ferrar                                                     *
  1170. * Created on: September 7, 1992                                               *
  1171. * Modified:                                                                   *
  1172. \*****************************************************************************/
  1173.  
  1174. void count_text3d(FILE *sff_file, char *this_line, long *num_objects)
  1175. {
  1176.  
  1177.     FILE    *sub_file;
  1178.     char    *subfilename;
  1179.     char    *text_string;
  1180.     short    i;
  1181.  
  1182.     /* Decide whether to read from this file or from another one */
  1183.     if (strstr(this_line, "-"))
  1184.     
  1185.         /* Use this file as the file */
  1186.         sub_file = sff_file;
  1187.     
  1188.     else    /* description is in another file */
  1189.         {
  1190.         
  1191.         /* get the filename to use */
  1192.         subfilename = (strrchr(this_line, ' ') + 1);
  1193.         
  1194.         /* chop off the '\n' */
  1195.         subfilename[strlen(subfilename) - 1] = 0;
  1196.         
  1197.         /* Open the file */
  1198.         sub_file = fopen (subfilename, "r");
  1199.  
  1200.         }
  1201.     
  1202.     /* Run through all lines */
  1203.     while (this_line [0] != '\n')
  1204.         {
  1205.         
  1206.         /* Check whether this line has a " on it */
  1207.         if (text_string = strstr (this_line, "\""))
  1208.             {
  1209.             
  1210.             /* move pointer to right after the " */
  1211.             text_string++;
  1212.  
  1213.             /* there are as many objects as non-space characters */
  1214.             i = 0;
  1215.             while (text_string[i] != '"')
  1216.                 if (text_string[i++] != ' ')
  1217.                     (*num_objects)++;
  1218.             
  1219.             }
  1220.         
  1221.         /* Go to next line */
  1222.         fgets(this_line, 10000, sub_file);
  1223.         
  1224.         }
  1225.     
  1226. }    /* count_text3d() */
  1227.  
  1228.  
  1229.  
  1230. /*****************************************************************************\
  1231. * procedure get_preferences                                                   *
  1232. *                                                                             *
  1233. * Purpose: This procedure gets the preferences from the Preferences folder in *
  1234. *          the System Folder of the startup disk.  If we are dealing with a   *
  1235. *          pre-System 7 system which does not have such a folder, we just get *
  1236. *          the preferences from the blessed folder.                           *
  1237. *                                                                             *
  1238. * Created by: Greg Ferrar                                                     *
  1239. * Created on: September 7, 1992                                               *
  1240. * Modified:                                                                   *
  1241. *   WHO          WHEN             WHAT                                        *
  1242. *   Greg Ferrar  9/10/92          Added support for pre-System 7 systems.     *
  1243. \*****************************************************************************/
  1244.  
  1245. void get_preferences(void)
  1246. {
  1247.  
  1248.  
  1249.     long    prefs_hard_dirid;
  1250.     long    num_bytes;
  1251.     short    prefs_folder_wd_id;
  1252.     short    prefs_vrefnum;
  1253.     short    error;
  1254.     
  1255.     preferences_struct *prefs_ptr;
  1256.     
  1257.     /* allocate the preferences structure */
  1258.     prefs_handle = (preferences_struct **) NewHandle(sizeof(preferences_struct));
  1259.  
  1260.     /* If we have FindFolder, use it.  Otherwise, use the blessed folder */
  1261.     if (find_folder_available)
  1262.         {
  1263.     
  1264.         /* Find the Preferences folder */
  1265.         error = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  1266.                             &prefs_vrefnum, &prefs_hard_dirid);
  1267.         if (error) terminal_startup_error(error);
  1268.     
  1269.         /* Make it a working directory */
  1270.         prefs_folder_wd_id = make_working_directory(prefs_vrefnum, prefs_hard_dirid);
  1271.     
  1272.         }
  1273.     else
  1274.  
  1275.         /* use the blessed folder */
  1276.         prefs_folder_wd_id = blessed_folder_wd_id;
  1277.  
  1278.  
  1279.     /* Open "MacRTrace Preferences" file */
  1280.     error = FSOpen (rtrace_prefs_filename, prefs_folder_wd_id, &preferences_file_refnum);
  1281.     
  1282.     /* If the file does not exist, create it */
  1283.     if (error == fnfErr)
  1284.  
  1285.         {
  1286.             
  1287.         /* Create and open the file */
  1288.         error = FSDelete (rtrace_prefs_filename, prefs_folder_wd_id);
  1289.         error = Create (rtrace_prefs_filename, prefs_folder_wd_id, 'RTRC', 'PREF');
  1290.         if (error) terminal_startup_error(error);
  1291.         error = FSOpen (rtrace_prefs_filename, prefs_folder_wd_id, &preferences_file_refnum);
  1292.         if (error) terminal_startup_error(error);
  1293.     
  1294.         /* Set the preferences structure according to the current preferences */
  1295.         write_preferences();
  1296.         
  1297.         }
  1298.     else if (error) terminal_startup_error(error);
  1299.  
  1300.         
  1301.     /* the file exists-- read the resources into memory */
  1302.         
  1303.     /* Read the preferences structure */
  1304.     SetFPos(preferences_file_refnum, 1, 0);
  1305.     num_bytes = sizeof(preferences_struct);
  1306.     FSRead(preferences_file_refnum, &num_bytes, *prefs_handle);
  1307.     
  1308.     /* lock the handle and dereference it */
  1309.     HLock(prefs_handle);
  1310.     prefs_ptr = *prefs_handle;
  1311.     
  1312.     /* Check the preferences version */
  1313.     if (prefs_ptr->prefs_version != CURRENT_PREFS_VERSION)
  1314.         {
  1315.         
  1316.         /* This an older preferences version-- delete the file and build
  1317.             a new one from defaults */
  1318.         error = FSClose (preferences_file_refnum);
  1319.         if (error) terminal_startup_error(error);
  1320.         error = FSDelete (rtrace_prefs_filename, prefs_folder_wd_id);
  1321.         if (error) terminal_startup_error(error);
  1322.         
  1323.         /* Get rid of handle, since we'll make a new one when we call ourselves */
  1324.         DisposHandle(prefs_handle);
  1325.         
  1326.         /* Call ourselves-- this will create a new preferences file */
  1327.         get_preferences();
  1328.         return;
  1329.         
  1330.         }
  1331.     
  1332.     /* Set the program defaults according to the preferences structure */
  1333.     place_window (log_window, &(prefs_ptr->log_window_position));
  1334.     place_window (options_dialog, &(prefs_ptr->options_window_position));
  1335.     place_window (status_dialog, &(prefs_ptr->status_window_position));
  1336.     if (f8bit_QD_available)
  1337.         place_window (image_window, &(prefs_ptr->image_window_position));
  1338.     place_window (animation_dialog, &(prefs_ptr->animation_window_position));
  1339.     show_image_rendering = prefs_ptr->show_image_rendering;
  1340.     allow_background_tasks = prefs_ptr->allow_background_tasks;
  1341.     keep_image_in_memory = prefs_ptr->keep_image_in_memory;
  1342.     show_status_window_flag = prefs_ptr->show_status_window_flag;
  1343.     show_about_window_flag = prefs_ptr->show_about_window_flag;
  1344.     hide_options_window_flag = prefs_ptr->hide_options_window_flag;
  1345.     time_between_events = prefs_ptr->time_between_events;
  1346.         
  1347.     /* get rid of the handle */
  1348.     HUnlock(prefs_handle);
  1349.  
  1350. }    /* get_preferences() */
  1351.  
  1352.  
  1353.  
  1354. /*****************************************************************************\
  1355. * procedure place_window                                                      *
  1356. *                                                                             *
  1357. * Purpose: This procedure moves and resizes a window to fit the passed Rect.  *
  1358. *          It ensure that the window has a dragable portion of its title bar  *
  1359. *          visible-- if not, it moves it to to main monitor.                  *
  1360. *                                                                             *
  1361. * Parameters: window: the window to move and resize                           *
  1362. *             bounds: the rectangle to move the window into.                  *
  1363. *                                                                             *
  1364. * Created by: Greg Ferrar                                                     *
  1365. * Created on: September 7, 1992                                               *
  1366. * Modified:                                                                   *
  1367. \*****************************************************************************/
  1368.  
  1369. short    make_working_directory(short vrefnum, long dir_id)
  1370. {
  1371.  
  1372.     WDPBRec    pb;
  1373.     short    error;
  1374.  
  1375.     pb.ioNamePtr = "\p";
  1376.     pb.ioWDProcID = 'RTRC';
  1377.     pb.ioWDDirID = dir_id;
  1378.     pb.ioVRefNum = vrefnum;
  1379.     error = PBOpenWD (&pb, FALSE);
  1380.     if (error) terminal_startup_error(error);
  1381.     
  1382.     /* Find the preferences working directory id */
  1383.     return (pb.ioVRefNum);
  1384.     
  1385. }    /* make_working_directory() */
  1386.  
  1387.  
  1388. /*****************************************************************************\
  1389. * procedure place_window                                                      *
  1390. *                                                                             *
  1391. * Purpose: This procedure moves and resizes a window to fit the passed Rect.  *
  1392. *          It ensure that the window has a dragable portion of its title bar  *
  1393. *          visible-- if not, it moves it to to main monitor.                  *
  1394. *                                                                             *
  1395. * Parameters: window: the window to move and resize                           *
  1396. *             bounds: the rectangle to move the window into.                  *
  1397. *                                                                             *
  1398. * Created by: Greg Ferrar                                                     *
  1399. * Created on: September 7, 1992                                               *
  1400. * Modified:                                                                   *
  1401. \*****************************************************************************/
  1402.  
  1403. void place_window (WindowPtr window, Rect *bounds)
  1404. {
  1405.  
  1406.     Rect        title_bar;        /* the rectangle enclosing the title bar of the window */
  1407.     Rect        intersection;    /* used to test rectangle intersections */
  1408.     Rect        first_bounds;    /* the boundary of the main graphics device */
  1409.     short        window_height;    /* the desired height of the window */
  1410.     short        window_width;    /* the desired width of the window */
  1411.     GDHandle    first_device;    /* the first graphics device on the the list */
  1412.     GDHandle    graphics_device;/* a graphics device on the the list */
  1413.     Boolean        enough_intersection = FALSE;
  1414.     Rect        rect_storage;
  1415.     WStateData    **wstate_handle;
  1416.     
  1417.     /* Find the first graphics device, and its bounding rectangle */
  1418.     first_device = graphics_device = GetDeviceList ();
  1419.     BlockMove(&((*first_device)->gdRect), &first_bounds, 8);
  1420.  
  1421.     /* If the rectangle is null, or the pointer is null it means the window
  1422.         was never shown before its position was saved, so we need to compute
  1423.         a new position. */
  1424.     if (((!bounds->right) && (!bounds->left) && (!bounds->top) && (!bounds->bottom)) ||
  1425.             !bounds)
  1426.         {
  1427.  
  1428.         /* Find the bounds of the window */
  1429.         bounds = &rect_storage;
  1430.         BlockMove (&(window->portRect), bounds, 8);
  1431.  
  1432.         /* Find the window's height and width */
  1433.         window_height = bounds->bottom - bounds->top;
  1434.         window_width = bounds->right - bounds->left;
  1435.  
  1436.  
  1437.         if (window == log_window)
  1438.                         
  1439.             /* Place the window in the upper left corner */
  1440.             OffsetRect(bounds, first_bounds.left + 4, first_bounds.top + 40);
  1441.  
  1442.         else if (window == options_dialog)            
  1443.             
  1444.             /* Place the window at the left, right below log window */
  1445.             OffsetRect(bounds, first_bounds.left + 4, log_window->portRect.bottom + 63);
  1446.         
  1447.         else if (window == image_window)
  1448.             
  1449.             /* Place the window below the status dialog and to the right of
  1450.                 the options dialog */
  1451.             OffsetRect(bounds, options_dialog->portRect.right + 10,
  1452.                         status_dialog->portRect.bottom + 63);
  1453.  
  1454.         else if (window == status_dialog)
  1455.             
  1456.             /* Place the window at the top, to the right of the log window */
  1457.             OffsetRect(bounds, log_window->portRect.right + 10, first_bounds.top + 40);
  1458.  
  1459.         else if (window == animation_dialog)
  1460.             
  1461.             /* Center the window on the main screen */
  1462.             OffsetRect(bounds, (first_bounds.right + first_bounds.left)/2 - (window_width/2),
  1463.                         (first_bounds.bottom + first_bounds.top)/2 - (window_height/2));
  1464.  
  1465.         else     /* any other window is centered on the screen */
  1466.                     
  1467.             /* Place the window in the "alert" position, in the upper center of the
  1468.                 main screen */
  1469.             OffsetRect(bounds, (first_bounds.right + first_bounds.left)/2 - (window_width/2),
  1470.                         (first_bounds.bottom + first_bounds.top)/3 - (window_height/2));
  1471.         
  1472.         /* Now use this new rectangle as a first approximation to place the window */
  1473.         place_window(window, bounds);    
  1474.         return;
  1475.         
  1476.         } 
  1477.  
  1478.     /* Find the window's height and width */
  1479.     window_height = bounds->bottom - bounds->top;
  1480.     window_width = bounds->right - bounds->left;
  1481.         
  1482.     /* Find the window's title bar */
  1483.     BlockMove(bounds, &title_bar, 8);
  1484.     title_bar.bottom = title_bar.top + 16;
  1485.     
  1486.     /* Scan through all the devices.  If there is any one device which has more than
  1487.         a 4x4 block of the title bar in it, we're okay. */
  1488.     do
  1489.         {
  1490.         SectRect (&title_bar, &((*graphics_device)->gdRect), &intersection);
  1491.         enough_intersection = (((intersection.bottom - intersection.top) >= 4) &&
  1492.                                 ((intersection.right - intersection.left) >= 4));
  1493.  
  1494.         graphics_device = (GDHandle) (*graphics_device)->gdNextGD;
  1495.         }
  1496.     while (graphics_device && (!enough_intersection));
  1497.  
  1498.     /* If no device has enough of an intersection, move this to the main window.
  1499.         We try to place it as close as possible to its original place, but we
  1500.         ensure that it's all on the main window (if possible). */
  1501.     if (!enough_intersection)
  1502.         {
  1503.         
  1504.         /* If the window is above the screen, pin it to the top */
  1505.         if ((bounds->bottom - 4) < first_bounds.top)
  1506.             {
  1507.             bounds->top = first_bounds.top + 41;
  1508.             bounds->bottom = bounds->top + window_height;
  1509.             }
  1510.         
  1511.         /* window was below screen-- pin it to the bottom */
  1512.         else
  1513.             {
  1514.             bounds->bottom = first_bounds.bottom - 5;
  1515.             bounds->top = bounds->bottom - window_height;
  1516.             }
  1517.  
  1518.         /* If the window is to the left of the screen, pin it to the left */
  1519.         if ((bounds->right - 4) < first_bounds.left)
  1520.             {
  1521.             bounds->left = first_bounds.left + 5;
  1522.             bounds->right = bounds->left + window_width;
  1523.             }
  1524.         
  1525.         /* window is to the right of the screen, pin it to the right */
  1526.         else
  1527.             {
  1528.             bounds->right = first_bounds.right - 8;
  1529.             bounds->left = bounds->right - window_width;
  1530.             }
  1531.         }
  1532.  
  1533.     /* Save the new location in the window record */
  1534.     wstate_handle = (WStateData **) ( (WindowPeek) window )->dataHandle;
  1535.     BlockMove(bounds, &(*wstate_handle)->userState, 8);
  1536.  
  1537.     /* Move the window to the new location */
  1538.     MoveWindow (window, bounds->left, bounds->top, TRUE);
  1539.     
  1540.     /* Resize the window */
  1541.     SizeWindow (window, window_width, window_height, TRUE);
  1542.     
  1543. }    /* place_window() */
  1544.  
  1545.  
  1546.  
  1547. /*****************************************************************************\
  1548. * procedure write_preferences                                                 *
  1549. *                                                                             *
  1550. * Purpose: This procedure writes the current preferences to the Preferences   *
  1551. *          Folder in the System Folder of the startup disk.                   *
  1552. *                                                                             *
  1553. * Created by: Greg Ferrar                                                     *
  1554. * Created on: September 7, 1992                                               *
  1555. * Modified:                                                                   *
  1556. \*****************************************************************************/
  1557.  
  1558. void write_preferences(void)
  1559. {
  1560.  
  1561.     long    num_bytes;
  1562.     short    error;
  1563.  
  1564.     /* Set the preferences structure according to the current preferences */
  1565.     update_preferences_handle();
  1566.  
  1567.     /* Write the preferences to the resource file */
  1568.     num_bytes = sizeof(preferences_struct);
  1569.     error = SetFPos(preferences_file_refnum, 1, 0);
  1570.     if (error) terminal_startup_error(error);
  1571.     error = FSWrite(preferences_file_refnum, &num_bytes, *prefs_handle);
  1572.     if (error) terminal_startup_error(error);
  1573.  
  1574. }    /* write_preferences() */
  1575.  
  1576.  
  1577.  
  1578. /*****************************************************************************\
  1579. * procedure update_preferences_handle                                         *
  1580. *                                                                             *
  1581. * Purpose: This procedure sets the preferences structure according to the     *
  1582. *          values of the current preferences.                                 *
  1583. *                                                                             *
  1584. * Created by: Greg Ferrar                                                     *
  1585. * Created on: September 7, 1992                                               *
  1586. * Modified:                                                                   *
  1587. \*****************************************************************************/
  1588.  
  1589. void update_preferences_handle(void)
  1590. {
  1591.  
  1592.     preferences_struct *prefs_ptr;
  1593.  
  1594.     /* lock the handle and dereference it */
  1595.     HLock(prefs_handle);
  1596.     prefs_ptr = *prefs_handle;
  1597.     
  1598.     /* Create the preferences structure, using the default values */
  1599.     prefs_ptr->prefs_version = CURRENT_PREFS_VERSION;
  1600.     remember_window_position(options_dialog, &(prefs_ptr->options_window_position));
  1601.     remember_window_position(log_window, &(prefs_ptr->log_window_position));
  1602.     remember_window_position(status_dialog, &(prefs_ptr->status_window_position));
  1603.     remember_window_position(image_window, &(prefs_ptr->image_window_position));
  1604.     remember_window_position(animation_dialog, &(prefs_ptr->animation_window_position));
  1605.     prefs_ptr->show_image_rendering = show_image_rendering;
  1606.     prefs_ptr->allow_background_tasks = allow_background_tasks;
  1607.     prefs_ptr->keep_image_in_memory = keep_image_in_memory;
  1608.     prefs_ptr->show_status_window_flag = show_status_window_flag;
  1609.     prefs_ptr->show_about_window_flag = show_about_window_flag;
  1610.     prefs_ptr->hide_options_window_flag = hide_options_window_flag;
  1611.     prefs_ptr->time_between_events = time_between_events;
  1612.  
  1613.     /* Unlock the handle */
  1614.     HUnlock(prefs_handle);
  1615.  
  1616. }
  1617.  
  1618.  
  1619.  
  1620. /*****************************************************************************\
  1621. * procedure remember_window_position                                          *
  1622. *                                                                             *
  1623. * Purpose: This procedure copies the current position of a window into a      *
  1624. *          rectangle structure, to save for later restoration.                *
  1625. *                                                                             *
  1626. * Created by: Greg Ferrar                                                     *
  1627. * Created on: September 7, 1992                                               *
  1628. * Modified:                                                                   *
  1629. \*****************************************************************************/
  1630.  
  1631. void remember_window_position(WindowPtr window, Rect *dest_rect)
  1632. {
  1633.  
  1634.     WStateData **wstate_handle;
  1635.  
  1636.     /* If this is the image window, and if we're running in 1-bit QD, don't
  1637.         even try to save it-- it doesn't exist */
  1638.     if ((window == image_window) && (!f8bit_QD_available))
  1639.         
  1640.         dest_rect->left = dest_rect->right = dest_rect->top = dest_rect->bottom = 0;
  1641.  
  1642.     else
  1643.         {
  1644.  
  1645.         /* Get the Window State data */
  1646.         wstate_handle = (WStateData **) ( (WindowPeek) window )->dataHandle;
  1647.  
  1648.         /* Copy it to the rectangle */
  1649.         BlockMove(&(*wstate_handle)->userState, dest_rect, 8);
  1650.  
  1651.         }
  1652.  
  1653. }
  1654.